package cn.mntool.ftp.core;


import cn.mntool.ftp.exception.ExceptionEnum;
import cn.mntool.ftp.exception.UploadException;
import cn.mntool.ftp.utils.OsUtils;
import com.alibaba.fastjson.JSONObject;
import com.jcraft.jsch.*;

import java.util.Properties;
import java.util.Vector;

/**
 * describe:sftp实现类
 *
 * @author lianying
 * @date 2018/12/13
 */
public class SftpManagerSupport extends FtpManager {

    /**
     * ftpConfig:ftp配置
     * sftp:sftp客户端
     * session:会话
     */
    private ChannelSftp sftp;
    private Session session;
    private FtpConfig ftpConfig;

    public SftpManagerSupport(FtpConfig ftpConfig) {
        this.ftpConfig = ftpConfig;
    }

    public ChannelSftp getSftp() {
        return sftp;
    }

    public Session getSession() {
        return session;
    }

    public FtpConfig getFtpConfig() {
        return ftpConfig;
    }

    @Override
    public boolean upload(String localPath, String remotePath) throws UploadException{
        java.io.File localFile = new java.io.File(localPath);
        if (!localFile.exists()) {
            throw new UploadException(ExceptionEnum.NOT_FOUND);
        }
        if (localFile.isFile()) {
            //是文件就调用上传文件。
            return uploadFile(localFile, remotePath);
        } else {
            //调用上传文件夹
            return uploadDir(localFile, remotePath);
        }
    }

    @Override
    protected boolean uploadFile(java.io.File localFile, String remotePath) {
        //保存当前路径
        String currentPath;
        try {
            currentPath=sftp.pwd();
        } catch (SftpException e) {
            e.printStackTrace();
            return false;
        }
        // 开始上传
        try {
            //如果远程目录不存在先创建
            if (!dirExist(remotePath)) {
                mkdirs(remotePath);
            }
            sftp.put(localFile.getAbsolutePath(), remotePath.length()<1?currentPath:remotePath);
            return true;
        } catch (SftpException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    protected boolean uploadDir(java.io.File localFile, String remotePath) {
        //如果远程路径不存在，直接创建
        if(!dirExist(remotePath))
        {
            mkdirs(remotePath);
        }
        //先保存现在所处的远程目录路径。
        String oldRemotePath;
        try {
            oldRemotePath=sftp.pwd();
        } catch (SftpException e) {
            //这部分异常直接上传失败
           return false;
        }
        //获取文件夹内部所有的文件
       java.io.File[] files=localFile.listFiles();
       //遍历判断文件数组，如果是文件就上传，如果是文件夹就创建，利用递归调用。
        for (int i=0;i<files.length;i++)
        {
            //先切换至远程路径下
            cd(remotePath);
            //如果是文件就调用上传文件的方法。
            if(files[i].isFile())
            {
                //当remotePath值为"",表示上传到当前目录
                uploadFile(files[i],"");
            }else {
                mkdir(files[i].getName());
                uploadDir(files[i],files[i].getName());
            }
        }
        //切换至旧的目录
        cd(oldRemotePath);
        return true;
    }

    @Override
    public boolean mkdirs(String dirPath) {
        //路径统一格式
        dirPath = OsUtils.path2Unite(dirPath);
        String[] paths = dirPath.split("/");
        //当前的路径保存
        String currentPath = "";
        for (int i = 0; i < paths.length; i++) {
            currentPath += paths[i];
            //如果当前需要创建的路径长度大于0
            if (currentPath.length() > 0) {
                //如果当前文件夹不存在才创建
                if (!dirExist(currentPath)) {
                    mkdir(currentPath);
                }
            }
            currentPath += "/";
        }
        return true;
    }

    /**
     * 删除文件夹或者文件
     *
     * @param filePath
     * @return
     */
    @Override
    public boolean delete(String filePath) {
        boolean result;
        if(dirExist(filePath))
        {
            result=deleteDir(filePath);
        }else {
            result=deleteFile(filePath);
        }
        return result;
    }

    @Override
    public boolean deleteFile(String filePath) {
        try {
            sftp.rm(filePath);
            return true;
        } catch (SftpException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean deleteDir(String dirPath) {
        try {
            //如果不是文件夹或者不存在，都直接返回false
            if(!dirExist(dirPath))
            {
                return false;
            }
            Vector vector=sftp.ls(dirPath);
            Object [] objects=vector.toArray();
            File[] files =new File[objects.length];
            for (int i = 0; i< files.length; i++)
            {
                String  js=JSONObject.toJSONString(objects[i]);
                files[i]=JSONObject.parseObject(js,File.class);
            }
            //循环所有File对象，判断是否是存在的文件夹，如果是就调用删除文件夹方法，这是一个递归。
            for (int i = 0; i< files.length; i++)
            {
                if(files[i].getFilename().equals("..")|| files[i].getFilename().equals("."))
                {
                    continue;
                }
                if(dirExist(dirPath+"/"+ files[i].getFilename()))
                {
                    deleteDir(dirPath+"/"+ files[i].getFilename());
                }else {
                    deleteFile(dirPath+"/"+ files[i].getFilename());
                }
            }
            sftp.rmdir(dirPath);
            return true;
        } catch (SftpException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean mkdir(String dirPath) {
        try {
            if(!dirExist(dirPath))
            {
                sftp.mkdir(dirPath);
                return true;
            }else {
                return false;
            }
        } catch (SftpException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean dirExist(String remotePath) {
        boolean value = false;
        try {
            //先保存当前路径，然后用cd的方式测试是否存在该路径，如果存在该路径要cd回原来的路径。
            String oldPath = sftp.pwd();
            value = cd(remotePath);
            cd(oldPath);
        } catch (SftpException e) {
            //如果异常直接判断失败
        }
        return value;
    }

    @Override
    public boolean login() throws JSchException {
        return connect();
    }

    @Override
    public boolean cd(String remotePath) {
        try {
            sftp.cd(remotePath);
        } catch (SftpException e) {
            return false;
        }
        return true;
    }

    @Override
    public void logOut() {
        if (null != sftp && sftp.isConnected()) {
            sftp.disconnect();
        }
        if (null != session && session.isConnected()) {
            session.disconnect();
        }
    }

    @Override
    public boolean connect() throws JSchException {
        JSch jsch = new JSch();
        // 按照用户名，主机ip，端口获取一个Session对象
            session = jsch.getSession(ftpConfig.getUserName(), ftpConfig.getHost(), ftpConfig.getPort());
            session.setPassword(ftpConfig.getPassWord());
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            config.put("UseDNS", "no");
            // 为Session对象设置properties
            session.setConfig(config);
            // 设置超时时间
            session.setTimeout(ftpConfig.getTimeOut());
            // 经由过程Session建树链接
            session.connect();
            sftp = (ChannelSftp) session.openChannel("sftp");
            // 建树SFTP通道的连接
            sftp.connect();
        return true;
    }
}
